﻿using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Settlements;
using TaleWorlds.CampaignSystem.Party;
using TaleWorlds.Core;
using TaleWorlds.CampaignSystem.Roster;
using TaleWorlds.Localization; 
using MarriageFertility.Helpers;
using MarriageFertility.Mcm;
using MarriageFertility.Texts; 

namespace MarriageFertility.Behaviors
{
    public class LordEquipmentOnEnterTownBehavior : CampaignBehaviorBase
    {
        private readonly struct ArmorSlot
        {
            public EquipmentIndex Index { get; }
            public ItemObject.ItemTypeEnum Type { get; }

            public ArmorSlot(EquipmentIndex index, ItemObject.ItemTypeEnum type)
            {
                Index = index;
                Type = type;
            }
        }

        private static readonly ArmorSlot[] ArmorSlots = new[]
        {
            new ArmorSlot(EquipmentIndex.Head, ItemObject.ItemTypeEnum.HeadArmor),
            new ArmorSlot(EquipmentIndex.Body, ItemObject.ItemTypeEnum.BodyArmor),
            new ArmorSlot(EquipmentIndex.Gloves, ItemObject.ItemTypeEnum.HandArmor),
            new ArmorSlot(EquipmentIndex.Leg, ItemObject.ItemTypeEnum.LegArmor),
            new ArmorSlot(EquipmentIndex.Cape, ItemObject.ItemTypeEnum.Cape)
        };

        public override void RegisterEvents()
        {
            CampaignEvents.SettlementEntered.AddNonSerializedListener(this, OnPartyEnteredSettlement);
        }

        private void OnPartyEnteredSettlement(MobileParty mobileParty, Settlement settlement, Hero hero)
        {
            if (settlement?.IsTown != true || mobileParty?.LeaderHero == null || !mobileParty.LeaderHero.IsLord || mobileParty.LeaderHero == Hero.MainHero)
                return;
            
            if(!MCMSettings.Instance.LordAutoTrade) return;

            UpgradeEquipment(mobileParty.LeaderHero, settlement);
        }

        private void UpgradeEquipment(Hero lord, Settlement settlement)
        {
            if (lord == null || settlement?.ItemRoster == null)
                return;

            ItemRoster itemRoster = settlement.ItemRoster;
            var purchaseMessages = new List<TextObject>(); // Changed to List<TextObject>

            purchaseMessages.AddRange(UpgradeWeapons(lord, itemRoster, settlement));
            purchaseMessages.AddRange(UpgradeArmor(lord, itemRoster, settlement));
            purchaseMessages.AddRange(UpgradeMountAndHarness(lord, itemRoster, settlement));
            purchaseMessages.AddRange(UpgradeAmmunition(lord, itemRoster, settlement));

            foreach (var message in purchaseMessages)
            {
                //InformationManager.DisplayMessage(new InformationMessage(message.ToString(), Colors.Green));
            }
        }

        private List<TextObject> UpgradeWeapons(Hero lord, ItemRoster itemRoster, Settlement settlement)
        {
            var messages = new List<TextObject>(); // Changed to List<TextObject>
            EquipmentIndex[] weaponSlots = { EquipmentIndex.WeaponItemBeginSlot, EquipmentIndex.Weapon1, EquipmentIndex.Weapon2 };

            foreach (var slot in weaponSlots)
            {
                EquipmentElement currentElement = lord.BattleEquipment[slot];
                bool isShieldSlot = slot == EquipmentIndex.Weapon1 && currentElement.Item?.ItemType == ItemObject.ItemTypeEnum.Shield;

                PurchaseBestItem(lord, itemRoster, settlement, slot, x =>
                    x.EquipmentElement.Item != null &&
                    x.Amount > 0 &&
                    (isShieldSlot
                        ? x.EquipmentElement.Item.ItemType == ItemObject.ItemTypeEnum.Shield
                        : x.EquipmentElement.Item.WeaponComponent != null &&
                          EquipmentUpdater.IsSameTypeWeapon(currentElement, x.EquipmentElement)) &&
                    !EquipmentUpdater.IsTooDifficult(x.EquipmentElement.Item, lord.CharacterObject) &&
                    EquipmentComparer.BetterWeapon(currentElement, x.EquipmentElement),
                    CalculateWeaponScore,
                    out TextObject message); // Changed to TextObject

                if (message != null)
                    messages.Add(message);
            }
            return messages;
        }

        public List<TextObject> UpgradeArmor(Hero lord, ItemRoster itemRoster, Settlement settlement)
        {
            var messages = new List<TextObject>(); // Changed to List<TextObject>

            foreach (var slot in ArmorSlots)
            {
                EquipmentElement currentElement = lord.BattleEquipment[slot.Index];

                PurchaseBestItem(lord, itemRoster, settlement, slot.Index, x =>
                    x.EquipmentElement.Item != null &&
                    x.Amount > 0 &&
                    x.EquipmentElement.Item.ItemType == slot.Type &&
                    EquipmentComparer.BetterArmor(lord.BattleEquipment, currentElement, x.EquipmentElement, slot.Index),
                    x => CalculateArmorScore(x, slot.Index),
                    out TextObject message); // Changed to TextObject

                if (message != null)
                    messages.Add(message);
            }
            return messages;
        }

        public List<TextObject> UpgradeMountAndHarness(Hero lord, ItemRoster itemRoster, Settlement settlement)
        {
            var messages = new List<TextObject>();
            EquipmentElement currentMount = lord.BattleEquipment[EquipmentIndex.Horse];

            PurchaseBestItem(lord, itemRoster, settlement, EquipmentIndex.Horse, x =>
                    x.EquipmentElement.Item != null &&
                    x.Amount > 0 &&
                    x.EquipmentElement.Item.ItemType == ItemObject.ItemTypeEnum.Horse &&
                    !EquipmentUpdater.IsTooDifficult(x.EquipmentElement.Item, lord.CharacterObject) &&
                    (currentMount.Item == null || x.EquipmentElement.Item.Effectiveness > currentMount.Item.Effectiveness),
                CalculateMountScore,
                out TextObject mountMessage);

            if (mountMessage != null)
            {
                messages.Add(mountMessage);
                lord.BattleEquipment[EquipmentIndex.HorseHarness] = new EquipmentElement(null);
            }

            if (!lord.BattleEquipment[EquipmentIndex.Horse].IsEmpty)
            {
                EquipmentElement currentHarness = lord.BattleEquipment[EquipmentIndex.HorseHarness];

                PurchaseBestItem(lord, itemRoster, settlement, EquipmentIndex.HorseHarness, x =>
                        x.EquipmentElement.Item != null &&
                        x.Amount > 0 &&
                        x.EquipmentElement.Item.ItemType == ItemObject.ItemTypeEnum.HorseHarness &&
                        EquipmentComparer.BetterHorseArmor(lord.BattleEquipment, currentHarness, x.EquipmentElement),
                    x => x.GetModifiedMountBodyArmor(),
                    out TextObject harnessMessage);

                if (harnessMessage != null)
                    messages.Add(harnessMessage);
            }

            return messages;
        }

        private List<TextObject> UpgradeAmmunition(Hero lord, ItemRoster itemRoster, Settlement settlement)
        {
            var messages = new List<TextObject>(); 
            EquipmentElement weapon = lord.BattleEquipment[EquipmentIndex.Weapon2];

            if (weapon.IsEmpty || (weapon.Item.ItemType != ItemObject.ItemTypeEnum.Bow && weapon.Item.ItemType != ItemObject.ItemTypeEnum.Crossbow))
                return messages;

            ItemObject.ItemTypeEnum ammoType = weapon.Item.ItemType == ItemObject.ItemTypeEnum.Bow ? ItemObject.ItemTypeEnum.Arrows : ItemObject.ItemTypeEnum.Bolts;
            EquipmentElement currentAmmo = lord.BattleEquipment[EquipmentIndex.Weapon3];

            PurchaseBestItem(lord, itemRoster, settlement, EquipmentIndex.Weapon3, x =>
                x.EquipmentElement.Item != null &&
                x.Amount > 0 &&
                x.EquipmentElement.Item.ItemType == ammoType &&
                EquipmentComparer.BetterWeapon(currentAmmo, x.EquipmentElement),
                CalculateAmmoScore,
                out TextObject message); // Changed to TextObject

            if (message != null)
                messages.Add(message);

            return messages;
        }

        private void PurchaseBestItem(Hero lord, ItemRoster itemRoster, Settlement settlement, EquipmentIndex slot,
            Func<ItemRosterElement, bool> filter, Func<EquipmentElement, double> scorer, out TextObject message) // Changed to TextObject
        {
            message = null;
            if (lord == null || itemRoster == null || settlement == null)
                return;
            
            var bestItem = itemRoster
                .Where(x => filter(x) && x.EquipmentElement.Item.Value <= lord.Gold)
                .OrderByDescending(x => scorer(x.EquipmentElement))
                .FirstOrDefault();

            if (bestItem.EquipmentElement.Item == null)
                return;

            ItemObject bestItemObject = bestItem.EquipmentElement.Item;
            lord.BattleEquipment[slot] = new EquipmentElement(bestItemObject);
            lord.Gold -= bestItemObject.Value;
            itemRoster.AddToCounts(bestItem.EquipmentElement, -1);

            message = MessageText.EquipmentPurchaseMessage.SetTextVariable("lord", lord.Name)
                .SetTextVariable("item", bestItemObject.Name)
                .SetTextVariable("value", bestItemObject.Value)
                .SetTextVariable("settlement", settlement.Name);
        }

        private double CalculateWeaponScore(EquipmentElement equipment)
        {
            if (equipment.Item?.WeaponComponent?.PrimaryWeapon == null)
                return 0;

            var primaryWeapon = equipment.Item.WeaponComponent.PrimaryWeapon;
            if (primaryWeapon.IsMeleeWeapon)
            {
                int swingDamage = equipment.GetModifiedSwingDamageForUsage(0);
                int thrustDamage = equipment.GetModifiedThrustDamageForUsage(0);
                int swingSpeed = equipment.GetModifiedSwingSpeedForUsage(0);
                int thrustSpeed = equipment.GetModifiedThrustSpeedForUsage(0);
                return 0.4 * (swingDamage + thrustDamage) + 0.3 * (swingSpeed + thrustSpeed);
            }
            else if (primaryWeapon.IsRangedWeapon)
            {
                int missileDamage = equipment.GetModifiedMissileDamageForUsage(0);
                int missileSpeed = equipment.GetModifiedMissileSpeedForUsage(0);
                return 0.5 * missileDamage + 0.3 * missileSpeed;
            }
            else if (primaryWeapon.WeaponClass == WeaponClass.SmallShield || primaryWeapon.WeaponClass == WeaponClass.LargeShield)
            {
                return equipment.Item.Effectiveness;
            }
            return 0;
        }

        private double CalculateArmorScore(EquipmentElement equipment, EquipmentIndex slot)
        {
            if (equipment.Item == null)
                return 0;

            double score = 0;
            if (slot == EquipmentIndex.Body || slot == EquipmentIndex.Cape)
            {
                score += equipment.GetModifiedHeadArmor();
                score += equipment.GetModifiedBodyArmor();
                score += equipment.GetModifiedLegArmor();
                score += equipment.GetModifiedArmArmor();
            }
            else if (slot == EquipmentIndex.Head)
            {
                score += equipment.GetModifiedHeadArmor();
            }
            else if (slot == EquipmentIndex.Gloves)
            {
                score += equipment.GetModifiedArmArmor();
            }
            else if (slot == EquipmentIndex.Leg)
            {
                score += equipment.GetModifiedLegArmor();
            }
            return score;
        }

        private double CalculateMountScore(EquipmentElement equipment)
        {
            if (equipment.Item?.HorseComponent == null)
                return 0;

            return equipment.Item.HorseComponent.Speed + 0.8 * equipment.Item.HorseComponent.Maneuver + 0.5 * equipment.Item.HorseComponent.BodyLength;
        }

        private double CalculateAmmoScore(EquipmentElement equipment)
        {
            if (equipment.Item?.WeaponComponent == null)
                return 0;

            int missileDamage = equipment.GetModifiedMissileDamageForUsage(0);
            int missileSpeed = equipment.GetModifiedMissileSpeedForUsage(0);
            return missileDamage + 0.1 * missileSpeed;
        }

        public override void SyncData(IDataStore dataStore)
        {
            
        }
    }
}